"""
策略抽象基类：定义策略接口规范
"""
import re
import pandas as pd
from typing import Dict
from abc import ABC
from datetime import date
from ..utils.logger import sys_logger

logger = sys_logger.getChild('Strategy')

class BaseStrategy(ABC):
    def __init__(self):
        """
        初始化策略
        :param symbols: 监控的标的列表
        """
        self._latest_data: Dict[str, Dict] = {}            # 各标的的最新股票数据
        self._history_data: Dict[str, pd.DataFrame] = {}   # 各标的的历史股价数据
        self._financial_data: Dict[str, pd.DataFrame] = {} # 各标的的历史财务数据
        
        self.risk = None
        self.portfolio = None
        
    def bind(self, engine):
        self.engine = engine
        self.risk = self.engine.risk
        self.portfolio = self.engine.portfolio
        self.market = self.engine.market

    @property
    def current_date(self):
        return self._current_date
        
    @current_date.setter    
    def current_date(self, date: date):
        self._current_date = date
        
    @staticmethod
    def _is_valid_symbol(symbol):
        """
        验证股票代码格式合法性
        合法格式示例：600000.SH 或 000001.SZ
        
        验证规则：
        1. 格式：6位数字.交易所代码
        2. 沪市（.SH）：60/688/900开头
        3. 深市（.SZ）：00/30/200开头
        """
        # 基础格式验证
        match = re.match(r"^(\d{6})\.([A-Za-z]{2})$", symbol)
        if not match:
            return False
        
        code, exchange = match.groups()
        exchange = exchange.upper()
        
        # 交易所代码验证
        if exchange not in ("SH", "SZ"):
            return False
        
        # 沪市代码规则验证
        if exchange == "SH":
            return any([
                code.startswith("60"),   # 主板
                code.startswith("688"),  # 科创板
                code.startswith("900")   # B股
            ])
        
        # 深市代码规则验证
        if exchange == "SZ":
            return any([
                code.startswith("00"),   # 主板/中小板
                code.startswith("30"),   # 创业板
                code.startswith("200")   # B股
            ])
        
        return False

    def load_latest_data(self, symbol: str, data: Dict) -> None:
        """加载标的的最新股票数据
        :param symbol: 标的代码
        :param data: 标的最新股票数据
        """
        self._latest_data[symbol] = data
        logger.debug("加载%s标的最新股票数据，最新股价 %.2f", symbol, data['lastPrice']) 
        
    def load_history_k_day_data(self, symbol: str, data: pd.DataFrame) -> None:
        """加载标的的历史股价数据
        :param symbol: 标的代码
        :param data: 包含DatetimeIndex的DataFrame（需有close字段）
        """
        if not isinstance(data.index, pd.DatetimeIndex):
            raise ValueError("历史股价数据索引必须是DatetimeIndex")
        
        self._history_data[symbol] = data.sort_index(ascending=True)
        logger.debug("加载%s标的历史股价数据 | 时间范围: %s ~ %s | 数据量: %d", 
                   symbol, data.index[0].date(), data.index[-1].date(), len(data)) 
        
    def load_financial_data(self, symbol: str, data: pd.DataFrame) -> None:
        """加载标的的历史财务数据
        :param symbol: 标的代码
        :param data: 包含DatetimeIndex的DataFrame（需有close字段）
        """
        if not isinstance(data.index, pd.DatetimeIndex):
            raise ValueError("历史财务数据索引必须是DatetimeIndex")
        
        self._financial_data[symbol] = data.sort_index(ascending=True)
        logger.debug("加载%s标的历史财务数据 | 时间范围: %s ~ %s | 数据量: %d", 
                   symbol, data.index[0].date(), data.index[-1].date(), len(data))         
        
        
    def pre_market(self) -> None:
        """执行开盘前准备"""
        pass

    def on_open(self) -> None:
        """执行开盘交易"""   
        pass
        
    def on_trade(self) -> None:
        """执行交易时段"""        
        pass
        
    def on_close(self) -> None:
        """执行收盘交易"""    
        pass
        
    def post_market(self) -> None:
        """执行收盘后记录"""    
        pass
